package cn.guetzjb.sys.controller;

import cn.guet.log.anotation.Log;
import cn.guet.log.enums.BusinessType;
import cn.guetzjb.core.entity.R;
import cn.guetzjb.security.anotation.RequiresPermissions;
import cn.guetzjb.security.anotation.RequiresRoles;
import cn.guetzjb.security.utils.SecurityUtils;
import cn.guetzjb.sys.domain.SysMenu;
import cn.guetzjb.sys.domain.SysMenuTree;
import cn.guetzjb.sys.domain.SysRoleMenu;
import cn.guetzjb.sys.service.SysMenuService;
import cn.guetzjb.sys.service.SysRoleMenuService;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import java.util.*;

@RestController
@RequestMapping("/menu")
@Tag(name = "菜单列表")
@RequiredArgsConstructor
public class MenuController {

    private final SysMenuService menuService;
    private final SysRoleMenuService roleMenuService;

    @GetMapping("/all")
    @Operation(summary = "获取(列表)", description = "根据权限获取菜单")
    public R getMenuList() {
        return R.ok(menuService.getMenuByAuth());
    }

    @GetMapping("/tree")
    @Operation(summary = "获取(树形)")
    public R getMenuTree() {
        List<SysMenu> menuList = menuService.getMenuByAuth();
        return R.ok(getMenuTree(menuList));
    }

    @GetMapping("/admin/tree")
    @Operation(summary = "菜单管理(树形)")
    @RequiresRoles(value = "admin")
    public R getAdminMenuTree() {
        List<SysMenu> menuList = menuService.list();
        return R.ok(getMenuTree(menuList));
    }

    private List<SysMenuTree> getMenuTree(List<SysMenu> menuList) {
        Map<Long, SysMenuTree> map = new HashMap<>();
        List<SysMenuTree> list = new ArrayList<>();
        for (SysMenu sysMenu : menuList) {
            SysMenuTree sysMenuTree = new SysMenuTree();
            BeanUtils.copyProperties(sysMenu, sysMenuTree);
            sysMenuTree.setKey(sysMenu.getMenuId());
            map.put(sysMenu.getMenuId(), sysMenuTree);
            if (sysMenu.getParentId() == 0L) {
                list.add(sysMenuTree);
            }
        }
        for (SysMenu sysMenu : menuList) {
            if (sysMenu.getParentId() == 0L) {
                continue;
            }
            if (map.containsKey(sysMenu.getParentId())) {
                map.get(sysMenu.getParentId()).getChildren().add(map.get(sysMenu.getMenuId()));
            }
        }
        for (SysMenu sysMenu : menuList) {
            if (sysMenu.getParentId() == 0L && map.containsKey(sysMenu.getMenuId())) {
                map.get(sysMenu.getMenuId()).getChildren().sort(Comparator.comparingInt(SysMenu::getOrderNum));
            }
        }
        return list;
    }

    @PostMapping("/add")
    @Operation(summary = "增加")
    @RequiresPermissions(value = {"menu:add"})
    @Log(title = "增加菜单", businessType = BusinessType.INSERT)
    public R addMenu(@RequestBody SysMenu sysMenu) {
        sysMenu.setCreateBy(SecurityUtils.getUsername());
        boolean b = menuService.saveOrUpdate(sysMenu);
        if (b) {
            return R.ok();
        } else {
            return R.failed();
        }
    }

    @PostMapping("/update")
    @Operation(summary = "修改")
    @Log(title = "修改菜单", businessType = BusinessType.UPDATE)
    @RequiresPermissions(value = {"menu:update"})
    public R updateMenu(@RequestBody SysMenu sysMenu) {
        sysMenu.setUpdateBy(SecurityUtils.getUsername());
        boolean b = menuService.updateById(sysMenu);
        if (b) {
            return R.ok();
        } else {
            return R.failed();
        }
    }

    @PostMapping("/delete/{ids}")
    @Operation(summary = "删除")
    @RequiresPermissions(value = {"menu:delete"})
    @Transactional
    @Log(title = "删除", businessType = BusinessType.DELETE)
    public R updateMenu(@PathVariable List<Integer> ids) {
        boolean b = menuService.removeBatchByIds(ids);
        boolean b2 = roleMenuService.remove(Wrappers.<SysRoleMenu>lambdaQuery().in(SysRoleMenu::getMenuId, ids));
        return R.ok(b && b2);
    }
}
